package org.kl.bf.web.basic;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.kl.bf.entity.basic.CodeValues;
import org.kl.bf.entity.basic.DataDetail;
import org.kl.bf.entity.basic.DataRole;
import org.kl.bf.entity.basic.Function;
import org.kl.bf.entity.basic.Menu;
import org.kl.bf.entity.basic.Role;
import org.kl.bf.entity.basic.User;
import org.kl.bf.entity.easyui.EasyuiTreeNode;
import org.kl.bf.entity.easyui.EasyuiUtils;
import org.kl.bf.entity.easyui.Json;
import org.kl.bf.service.basic.DataDetailService;
import org.kl.bf.service.basic.FunctionService;
import org.kl.bf.service.basic.UserService;
import org.kl.bf.utils.KLServlets;
import org.kl.bf.web.base.BasicController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springside.modules.web.MediaTypes;

import com.github.abel533.echarts.Option;
import com.github.abel533.echarts.code.BrushType;
import com.github.abel533.echarts.code.Magic;
import com.github.abel533.echarts.code.Tool;
import com.github.abel533.echarts.code.Trigger;
import com.github.abel533.echarts.code.X;
import com.github.abel533.echarts.code.Y;
import com.github.abel533.echarts.feature.MagicType;
import com.github.abel533.echarts.series.Force;
import com.github.abel533.echarts.series.force.Link;
import com.github.abel533.echarts.series.force.Node;
import com.github.abel533.echarts.style.ItemStyle;

/**
 * 用户权限查看
 * 
 * @author ymc
 * @date 2014-3-24
 */
@Controller
@RequestMapping(value = "/basic/userPermission")
public class UserPermissionController extends BasicController {
	@Autowired
	private UserService userService;
	@Autowired
	private DataDetailService dataDetailService;
	@Autowired
	private FunctionService functionService;

	private static Integer i = 0;

	@RequiresPermissions("userPermission:list")
	@RequestMapping(method = RequestMethod.GET)
	public String list() {
		return "basic/userPermissionList";
	}

	@RequiresPermissions("userPermission:list")
	@RequestMapping(value = "userDataGrid", produces = MediaTypes.JAVASCRIPT_UTF_8)
	@ResponseBody
	public String userDataGrid(@RequestParam(value = "pageNumber", defaultValue = "1") int pageNumber,
			@RequestParam(value = "rows", defaultValue = PAGE_SIZE) int pageSize,
			@RequestParam(value = "sort", defaultValue = "id") String sortType,
			@RequestParam(value = "order", defaultValue = "desc") String orderType, Model model, ServletRequest request) {
		Map<String, Object> searchParams = KLServlets.getParametersStartingWith(request, SEARCH_PREFIX);
		Page<User> users = userService.getUser(searchParams, pageNumber, pageSize, sortType, orderType);
		return EasyuiUtils.buildEasyuiGridJsonString(users.getContent(), (int) users.getTotalElements());
	}

	@RequiresPermissions("userPermission:list")
	@RequestMapping(value = "roleTree/{userId}", method = RequestMethod.GET, produces = MediaTypes.JAVASCRIPT_UTF_8)
	@ResponseBody
	public String roleTree(@PathVariable("userId") String id, Model model, ServletRequest request) {
		List<Role> roleList = new ArrayList<Role>();
		Json json = new Json();
		if (StringUtils.isNotBlank(id)) {
			Set<Role> roleSet = userService.getUser(id).getRoleSet();
			if (!roleSet.isEmpty()) {
				json.setMsg("加载成功。");
				Iterator<Role> it = roleSet.iterator();
				while (it.hasNext()) {
					Role r = it.next();
					roleList.add(r);
				}
				json.setSuccess(true);
				List<EasyuiTreeNode> plainTree = new ArrayList<EasyuiTreeNode>();
				for (Role r : roleList) {
					EasyuiTreeNode one = roleToTreeNode(r);
					plainTree.add(one);
				}
				json.setObj(plainTree);
			} else {
				json.setMsg("该用户的角色权限为空！");
				json.setSuccess(false);
				json.setObj(null);
			}
		}

		return jsonMapper.toJson(json);
	}

	private EasyuiTreeNode roleToTreeNode(Role role) {
		EasyuiTreeNode one = new EasyuiTreeNode();
		one.setId(role.getId());
		one.setText(role.getRoleName());
		Set<Menu> menuSet = role.getRoleMenus();
		Iterator<Menu> it = menuSet.iterator();
		List<EasyuiTreeNode> menuTree = new ArrayList<EasyuiTreeNode>();
		while (it.hasNext()) {
			Menu m = it.next();
			EasyuiTreeNode two = menuToFunction(role, m);
			menuTree.add(two);
		}
		one.setChildren(menuTree);
		return one;
	}

	private EasyuiTreeNode menuToFunction(Role r, Menu m) {
		EasyuiTreeNode two = new EasyuiTreeNode();
		two.setId(m.getId());
		two.setText(m.getMenuName());
		two.setPid(r.getId());
		List<Function> funcList = functionService.getFunctionByMenuId(m.getId());
		List<EasyuiTreeNode> funTree = new ArrayList<EasyuiTreeNode>();
		for (Function f : funcList) {
			EasyuiTreeNode three = functionNode(f);
			funTree.add(three);
		}
		two.setChildren(funTree);
		return two;
	}

	private EasyuiTreeNode functionNode(Function f) {
		EasyuiTreeNode three = new EasyuiTreeNode();
		three.setId(f.getId());
		three.setText(f.getFunctionName());
		three.setPid(f.getMenu().getId());
		return three;
	}

	@RequiresPermissions("userPermission:list")
	@RequestMapping(value = "dataRoleTree/{userId}", method = RequestMethod.GET, produces = MediaTypes.JAVASCRIPT_UTF_8)
	@ResponseBody
	public String dataRoleTree(@PathVariable("userId") String id, Model model, ServletRequest request) {
		Json json = new Json();
		List<DataRole> dataRoleList = new ArrayList<DataRole>();
		if (StringUtils.isNotBlank(id)) {
			Set<DataRole> dataRoleSet = userService.getUser(id).getDataRoleSet();
			if (!dataRoleSet.isEmpty()) {
				Iterator<DataRole> it = dataRoleSet.iterator();
				while (it.hasNext()) {
					DataRole d = it.next();
					dataRoleList.add(d);
				}
				json.setMsg("加载成功。");
				json.setSuccess(true);
				List<EasyuiTreeNode> plainTree = new ArrayList<EasyuiTreeNode>();
				for (DataRole d : dataRoleList) {
					EasyuiTreeNode one = dataRoleToTreeNode(d);
					plainTree.add(one);
				}
				json.setObj(plainTree);
			} else {
				json.setMsg("该用户数据角色为空！");
				json.setSuccess(false);
				json.setObj(null);
			}
		}

		return jsonMapper.toJson(json);
	}

	private EasyuiTreeNode dataRoleToTreeNode(DataRole d) {
		EasyuiTreeNode one = new EasyuiTreeNode();
		one.setId(d.getId());
		one.setText(d.getDataRoleName());
		List<CodeValues> codeValuesList = dataDetailService.getALLCodeName();
		for (int j = codeValuesList.size() - 1; j >= 0; j--) {
			int n = 0;
			Iterator<DataDetail> i = d.getDataDetailSet().iterator();
			while (i.hasNext()) {
				DataDetail dd = i.next();
				if (StringUtils.equals(dd.getDataType().getId(), codeValuesList.get(j).getId())) {
					n = 1;
					break;
				}
			}
			if (n == 0) {
				codeValuesList.remove(j);
			}
		}
		List<EasyuiTreeNode> dataDetailTypeTree = new ArrayList<EasyuiTreeNode>();
		for (CodeValues c : codeValuesList) {
			EasyuiTreeNode two = dataDetailType(d, c);
			dataDetailTypeTree.add(two);
		}
		one.setChildren(dataDetailTypeTree);
		return one;
	}

	private EasyuiTreeNode dataDetailType(DataRole d, CodeValues c) {
		EasyuiTreeNode two = new EasyuiTreeNode();
		i++;
		two.setId(i.toString());
		two.setText(c.getCodeName());
		two.setPid(d.getId());
		Set<DataDetail> dataDetailList = d.getDataDetailSet();// dataDetailService.getDataDetailListBydataTypeName(c.getCodeName());
		List<EasyuiTreeNode> dataDetailTree = new ArrayList<EasyuiTreeNode>();
		for (DataDetail data : dataDetailList) {
			if (StringUtils.equals(data.getDataType().getId(), c.getId())) {
				EasyuiTreeNode three = dataDetailNode(data);
				dataDetailTree.add(three);
			}
		}
		two.setChildren(dataDetailTree);
		return two;
	}

	private EasyuiTreeNode dataDetailNode(DataDetail da) {
		EasyuiTreeNode three = new EasyuiTreeNode();
		three.setId(da.getId());
		three.setText(da.getDataName());
		three.setPid(i.toString());
		return three;
	}

	/**
	 * 所有RequestMapping方法调用前的Model准备方法, 实现Struts2
	 * Preparable二次部分绑定的效果,先根据form的id从数据库查出Task对象,再把Form提交的内容绑定到该对象上。
	 * 因为仅update()方法的form中有id属性，因此仅在update时实际执行.
	 */
	@ModelAttribute
	public void getUser(@RequestParam(value = "id", defaultValue = "-1") String id, Model model) {
		if (!id.equals("-1")) {
			model.addAttribute("user", userService.getUser(id));
		}
	}

	// *******************************************************图形化显示用户权限*************************************************************
	@RequiresPermissions("userPermission:list")
	@RequestMapping(value = "graphicalUserPermission/{userId}", method = RequestMethod.GET, produces = MediaTypes.JAVASCRIPT_UTF_8)
	@ResponseBody
	public String graphicalUserPermission(@PathVariable("userId") String id) {
		if (StringUtils.isNotBlank(id)) {
			ItemStyle itemStyle = new ItemStyle();
			itemStyle.normal().label().show(true).textStyle().color("#333");
			itemStyle.normal().nodeStyle().brushType(BrushType.both).borderColor("rgba(255,215,0,0.6)").borderWidth(1);
			Option option = new Option();
			option.title().text("组织结构").x(X.center).y(Y.bottom);
			option.tooltip().trigger(Trigger.item).formatter("{a} : {b}");
			option.toolbox().show(true).feature(Tool.restore, new MagicType(Magic.force, Magic.chord), Tool.saveAsImage);
			option.legend().x(X.left).data("人员", "角色", "权限界面", "界面权限", "数据角色", "数据类型", "数据权限");
			Force f = new Force();
			List<Node> nodes = new ArrayList<>();
			List<Link> links = new ArrayList<>();
			getNodeAndLink(id, nodes, links);
			if (nodes.size() != 1) {
				f.name("人员权限").categories("人员", "角色", "权限界面", "界面权限", "数据角色", "数据类型", "数据权限").minRadius(4).maxRadius(10).coolDown(0.995)
						.steps(10).nodes(nodes).links(links);
				option.series(f);
			}
			return ajaxMsg("获取成功", true, option);
		} else {
			return ajaxMsg("获取失败", false, null);
		}
	}

	private void getNodeAndLink(String id, List<Node> nodes, List<Link> links) {
		User u = userService.getUser(id);
		Node n = new Node();
		n.category(0);
		n.name(u.getTrueName());
		n.value(10);
		nodes.add(n);
		List<Role> roleList = new ArrayList<Role>();
		Set<Role> roleSet = userService.getUser(id).getRoleSet();
		if (!roleSet.isEmpty()) {
			Iterator<Role> it = roleSet.iterator();
			while (it.hasNext()) {
				Role r = it.next();
				roleList.add(r);
			}
			for (Role r : roleList) {
				Node one = roleToNode(r);
				Link two = roleToLink(u, r);
				nodes.add(one);
				links.add(two);
				Set<Menu> menuSet = r.getRoleMenus();
				Iterator<Menu> iMenu = menuSet.iterator();
				while (iMenu.hasNext()) {
					Menu m = iMenu.next();
					one = menuToNode(m);
					two = menuToLink(r, m);
					nodes.add(one);
					links.add(two);
					List<Function> funcList = functionService.getFunctionByMenuId(m.getId());
					for (Function f : funcList) {
						one = functionToNode(m, f);
						two = functionToLink(m, f);
						nodes.add(one);
						links.add(two);
					}
				}
			}
		}
		Set<DataRole> dataRoleSet = u.getDataRoleSet();
		if (!dataRoleSet.isEmpty()) {
			Iterator<DataRole> it = dataRoleSet.iterator();
			while (it.hasNext()) {
				DataRole d = it.next();
				Node one = dataRoleToNode(d);
				Link two = dataRoleToLink(u, d);
				nodes.add(one);
				links.add(two);
				List<CodeValues> codeValuesList = dataDetailService.getALLCodeName();
				for (int j = codeValuesList.size() - 1; j >= 0; j--) {
					int num = 0;
					Iterator<DataDetail> i = d.getDataDetailSet().iterator();
					while (i.hasNext()) {
						DataDetail dd = i.next();
						if (StringUtils.equals(dd.getDataType().getId(), codeValuesList.get(j).getId())) {
							num = 1;
							break;
						}
					}
					if (num == 0) {
						codeValuesList.remove(j);
					}
				}
				for (CodeValues c : codeValuesList) {
					one = codeValuesToNode(c);
					two = codeValuesToLink(d, c);
					nodes.add(one);
					links.add(two);
					Set<DataDetail> dataDetailList = d.getDataDetailSet();
					for (DataDetail data : dataDetailList) {
						if (StringUtils.equals(data.getDataType().getId(), c.getId())) {
							one = dataDetailToNode(data);
							two = dataDetailToLink(c, data);
							nodes.add(one);
							links.add(two);
						}
					}
				}
			}
		}
	}

	private Node roleToNode(Role role) {
		Node one = new Node();
		one.category(1);
		one.name(role.getRoleName());
		one.value(8);
		return one;
	}

	private Node menuToNode(Menu m) {
		Node one = new Node();
		one.category(2);
		one.name(m.getMenuName());
		one.value(6);
		return one;
	}

	private Node functionToNode(Menu menu, Function f) {
		Node one = new Node();
		one.category(3);
		one.name(menu.getMenuName() + "/" + f.getFunctionName());
		one.value(4);
		return one;
	}

	private Link roleToLink(User user, Role role) {
		Link one = new Link();
		one.source(role.getRoleName());
		one.target(user.getTrueName());
		one.weight(1);
		return one;
	}

	private Link menuToLink(Role role, Menu menu) {
		Link one = new Link();
		one.target(role.getRoleName());
		one.source(menu.getMenuName());
		one.weight(1);
		return one;
	}

	private Link functionToLink(Menu menu, Function function) {
		Link one = new Link();
		one.source(menu.getMenuName() + "/" + function.getFunctionName());
		one.target(menu.getMenuName());
		one.weight(1);
		return one;
	}

	private Node dataRoleToNode(DataRole dataRole) {
		Node one = new Node();
		one.category(4);
		one.name(dataRole.getDataRoleName());
		one.value(7);
		return one;
	}

	private Node codeValuesToNode(CodeValues codeValues) {
		Node one = new Node();
		one.category(5);
		one.name("数据类型-" + codeValues.getCodeName());
		one.value(5);
		return one;
	}

	private Node dataDetailToNode(DataDetail dataDetail) {
		Node one = new Node();
		one.category(6);
		one.name(dataDetail.getDataName());
		one.value(3);
		return one;
	}

	private Link dataRoleToLink(User user, DataRole dataRole) {
		Link one = new Link();
		one.source(dataRole.getDataRoleName());
		one.target(user.getTrueName());
		one.weight(1);
		return one;
	}

	private Link codeValuesToLink(DataRole dataRole, CodeValues codeValues) {
		Link one = new Link();
		one.source("数据类型-" + codeValues.getCodeName());
		one.target(dataRole.getDataRoleName());
		one.weight(1);
		return one;
	}

	private Link dataDetailToLink(CodeValues codeValues, DataDetail dataDetail) {
		Link one = new Link();
		one.source(dataDetail.getDataName());
		one.target("数据类型-" + codeValues.getCodeName());
		one.weight(1);
		return one;
	}
}
